/* Start Header
*****************************************************************/
/*!
\file   Timer.cpp
\author <Liu Wei Long, weilong.liu, 250002510>
        <Liu Zhi Yang, zhiyang.liu, 300000111>
\par    <email: weilong.liu\@digipen.edu> 
        <email: zhiyang.liu\@digipen.edu> 
\date   <Apr 3, 2012>
\brief
Copyright (C) 2012 DigiPen Institute of Technology.
Reproduction or disclosure of this file or its contents without the
prior written consent of DigiPen Institute of Technology is prohibited.
*/
/* End Header
*******************************************************************/
#include "Timer.h"

#define TIMEOUT_DURATION 50

/******************************************************************************/
/*!
	\brief
		Check if it is a valid timer ID 
*/
/******************************************************************************/
bool Timer::IsTimerEventValid( unsigned int unID )
{

	std::list<TimerEvent*>::iterator begin = teList.begin(),
									 end   = teList.end();

	while (begin != end)
	{
		if ((*begin)->unTimerID == unID)
		{
			return true;
		}

		++begin;
	}

	return false;

}

/******************************************************************************/
/*!
	\brief
    Updates all timer with the latest timing
*/
/******************************************************************************/
void Timer::Update()
{
	QueryPerformanceCounter(&currentTime);
	float dt = (currentTime.QuadPart - previousTime.QuadPart) / (float)frequency.QuadPart;

	std::list<TimerEvent*>::iterator begin = teList.begin(),
									 end   = teList.end();

	while (begin != end)
	{
		if (!(*begin)->bIsComplete)
		{
			(*begin)->fCurr += dt;

			if ((*begin)->fCurr > (*begin)->fTotal)
			{
				(*begin)->bIsComplete = true;

			}
		}

		++begin;
	}


	previousTime = currentTime;
}

/******************************************************************************/
/*!
	\brief
    Check if timer is completed or reached the given time lapsed
*/
/******************************************************************************/
bool Timer::IsTimerEventComplete( unsigned int unID )
{
	std::list<TimerEvent*>::iterator begin = teList.begin(),
		end    = teList.end();

	while (begin != end)
	{
		if ((*begin)->unTimerID == unID)
		{
			if ((*begin)->bIsComplete)
			{
				if ((*begin)->bIsRepeat)
				{
					(*begin)->unCount++;

					if ((*begin)->unCount == (*begin)->unTotalCount)
					{
						teList.erase(begin);
					}
					else
					{
						(*begin)->bIsComplete = false;
						(*begin)->fCurr = 0;
					}
				}
				else
				{
					teList.erase(begin);
				}
				return true;
			}

			return false;
		}

		++begin;
	}

	return false;
}

/******************************************************************************/
/*!
	\brief
    Create a timer event that specifies how long the timer should elapsed
*/
/******************************************************************************/
unsigned int Timer::CreateTimerEvent( float fTime, bool bRepeat, unsigned int unRepeatCount )
{
	TimerEvent *teNewTimer = new TimerEvent;
	teNewTimer->unTimerID = unIDCount++;
	teNewTimer->fTotal = (long double)fTime;
	teNewTimer->fCurr = 0.0f;
	teNewTimer->bIsComplete = false;
	teNewTimer->unCount = 0;
	teNewTimer->unTotalCount = unRepeatCount;
	teNewTimer->bIsRepeat = bRepeat;
	teList.push_back(teNewTimer);

	return teNewTimer->unTimerID;
}

/******************************************************************************/
/*!
	\brief
    Retrieve the current time
*/
/******************************************************************************/
LARGE_INTEGER Timer::GetTime( void )
{
	QueryPerformanceCounter  (&currentTime);

	return currentTime;
}

/******************************************************************************/
/*!
	\brief
    Check if the timer has exceeded the timeout duration
*/
/******************************************************************************/
bool Timer::DiffTimeVal(LARGE_INTEGER start, LARGE_INTEGER end)
{
	QueryPerformanceFrequency(&frequency);

	float test = (end.QuadPart - start.QuadPart) * 1000.0f / frequency.QuadPart;

	return test > TIMEOUT_DURATION;
}

/******************************************************************************/
/*!
	\brief
    Compute the time taken from start to end
*/
/******************************************************************************/
float Timer::GetTimeDiff(LARGE_INTEGER start, LARGE_INTEGER end)
{
	QueryPerformanceFrequency(&frequency);

	float timetaken = (end.QuadPart - start.QuadPart) * 1000.0f / frequency.QuadPart;

	return timetaken;
}
